package tp.pr4.cityLoader;

import java.io.*;
import java.util.*;
import tp.pr4.*;
import tp.pr4.cityLoader.cityLoaderExceptions.WrongCityFormatException;
import tp.pr4.items.*;

/*
 * 
 BeginCity
 BeginPlaces
 place 0 Entrada Estamos_en_la_entrada._Comienza_la_aventura noSpaceShip
 place 1 Callao In_this_square... spaceShip
 ...
 EndPlaces
 BeginStreets
 street 0 place 0 south place 1 open
 street 1 place 1 east place 2 open
 street 2 place 2 north place 3 closed onetwothreefourfive
 ...
 EndStreets
 BeginItems
 fuel 0 Petrol from_olds_heatings 10 3 place 0
 fuel 1 Battery to_get_cracking -50 1 place 0
 codecard 2 Card The_key_is_too_easy onetwothreefourfive place 1
 garbage 3 Newspapers News_on_sport 30 place 2
 ...
 EndItems
 EndCity
 
 * */
public class CityLoaderFromTxtFile {
	private ArrayList<Place> places;
	private ArrayList<Street> streets;
	private ArrayList<Item> items;
	//private City parsedCity;
	
	final String BEGINCITY = "BeginCity";
	final String ENDCITY = "EndCity";
	final String BEGINSTREETS = "BeginStreets";
	final String ENDSTREETS = "EndStreets";
	final String BEGINPLACES = "BeginPlaces";
	final String ENDPLACES = "EndPlaces";
	final String BEGINITEMS = "BeginItems";
	final String ENDITEMS = "EndItems";
	/**
	 * Default constructor
	 */
	public CityLoaderFromTxtFile(){
		this.places = new ArrayList<Place>();
		this.streets = new ArrayList<Street>();
		this.items = new ArrayList<Item>();
		//this.parsedCity = new City();
	}
	
	/**
	 * returns the items ArrayList
	 * @return
	 */
	public ArrayList<Item> getItemsHashMap(){
		return this.items;
	} 
	/**
	 * returns the streets arraylist
	 * @return
	 */
	public ArrayList<Street> getStreetsHashMap(){
		return this.streets;
	} 
	/**
	 * returns the places arraylist
	 * @return
	 */
	public ArrayList<Place> getPlaceArrayList(){
		return this.places;
	} 
	/**
	 * returns the first place, which will be the initial one
	 * @return
	 */
	public Place getInitialPlace(){
		return places.get(0);
	}
	/**
	 * Parses a portion of the line between " symbols into a legible format with _ instead of spaces
	 * @param line
	 * @return
	 */
	private String parseComillas(String line){
		String comillas ="\"";
		if(line != null){
			if(line.contains(comillas)){
				String[] arrLine = line.split(comillas);
				arrLine[1] = arrLine[1].replace(" ", "_");
				return arrLine[0] + arrLine[1] + arrLine[2];
			}else{
				return line;
			}	
		}else{
			return line;
		}
	}
	/**
	 * loads a city from the file in the inputstream given
	 * @param file
	 * @return
	 * @throws java.io.IOException
	 * @throws WrongCityFormatException
	 */
	public City loadCity(InputStream file) throws java.io.IOException, WrongCityFormatException{
		
		City city = new City();
		
		BufferedReader in = new BufferedReader(new InputStreamReader(file));
		String line = in.readLine();
		if(line != null){
			if(line.equals(BEGINCITY)){
				line = in.readLine();
				if(line != null){
					while(!line.equals(ENDCITY)) {						
						if(line.equals(BEGINPLACES)){
							parsePlaces(in);
						}else if(line.equals(BEGINSTREETS)){
							parseStreets(in, city);
						}else if(line.equals(BEGINITEMS)){
							parseItems(in);
						}							
						if((line = in.readLine())==null) throw new WrongCityFormatException();						
					}
				}else{
					throw new WrongCityFormatException();
				}
			}		
		}else{
			throw new WrongCityFormatException();
		}
		return city;
	}
	/**
	 * parses the lines between BeginItems and EndItems
	 * @param in
	 * @throws java.io.IOException
	 * @throws WrongCityFormatException
	 */
	private void parseItems(BufferedReader in) throws java.io.IOException, WrongCityFormatException{
		String line = null;
		int lastInd = -1;
		line = parseComillas(in.readLine());
		if(line != null){
			while(!line.equals(ENDITEMS)) {
				String[] arrItem = line.trim().replaceAll(" +", " ").split(" ");
				if(arrItem.length >= 3){
					if (Integer.parseInt(arrItem[1]) == lastInd+1 ){	
						Item it = null;
						if(arrItem[0].equals(new String("fuel")) && arrItem.length > 7){//empieza por place
							it = new Fuel(arrItem[2],arrItem[3].replace("_"," "),Integer.parseInt(arrItem[4]),Integer.parseInt(arrItem[5]));	
							if(places.size() >= Integer.parseInt(arrItem[arrItem.length-1])){
								items.add(it);
								places.get(Integer.parseInt(arrItem[arrItem.length-1])).addItem(it);												
							}else{
								throw new WrongCityFormatException();
							}
						}else if(arrItem[0].equals(new String("codecard"))  && arrItem.length > 6){
							it=new CodeCard(arrItem[2],arrItem[3].replace("_"," "),arrItem[4]);	
							if(places.size() >= Integer.parseInt(arrItem[arrItem.length-1])){
								items.add(it);
								places.get(Integer.parseInt(arrItem[arrItem.length-1])).addItem(it);
												
							}else{
								throw new WrongCityFormatException();
							}
						}else if(arrItem[0].equals(new String("garbage"))  && arrItem.length > 6){
							it=new Garbage(arrItem[2],arrItem[3].replace("_"," "),Integer.parseInt(arrItem[4]));
							if(places.size() >= Integer.parseInt(arrItem[arrItem.length-1])){
								items.add(it);
								places.get(Integer.parseInt(arrItem[arrItem.length-1])).addItem(it);
												
							}else{
								throw new WrongCityFormatException();
							}
						}else{
							throw new WrongCityFormatException();
						}
						
						//System.out.println(arrItem.length-1);
						lastInd++;
						
					}else{
						throw new WrongCityFormatException();
					}
				}else{
					throw new WrongCityFormatException();
				}
				if((line = parseComillas(in.readLine()))==null) throw new WrongCityFormatException();
			}
		}else{
			throw new WrongCityFormatException();
		}
	}
	/**
	 * Parses the places between BeginPlaces and EndPlaces
	 * @param in
	 * @throws java.io.IOException
	 * @throws WrongCityFormatException
	 */
	private void parsePlaces(BufferedReader in) throws java.io.IOException, WrongCityFormatException{		
		String line = null;
		int lastInd = -1;
		line = parseComillas(in.readLine());
		if(line != null){
			while(!line.equals(ENDPLACES)) {
				String[] arrPlace = line.trim().replaceAll(" +", " ").split(" ");
				if(arrPlace.length >= 5){
					if(arrPlace[0].equals(new String("place")) && Integer.parseInt(arrPlace[1]) == ++lastInd){//empieza por place				
						places.add(new Place(arrPlace[2],("spaceShip".equals(arrPlace[4])),arrPlace[3].replace("_", " ")));
						
					}else{
						throw new WrongCityFormatException();
					}
				}else{
					throw new WrongCityFormatException();
				}
				if((line = parseComillas(in.readLine()))==null) throw new WrongCityFormatException();
			}
		}else{
			throw new WrongCityFormatException();
		}
	}
	/**
	 * Parses the streets between BeginStreets and EndStreets
	 * @param in
	 * @param city
	 * @throws java.io.IOException
	 * @throws WrongCityFormatException
	 */
	private void parseStreets(BufferedReader in, City city) throws java.io.IOException, WrongCityFormatException{
		String line = null;
		int lastInd = -1;
		line = in.readLine();
		if(line != null){
			while(!line.equals(ENDSTREETS) && line != null) {
				String[] arrStreet = line.trim().replaceAll(" +", " ").split(" ");
				if(arrStreet.length >=8){
					if(arrStreet[0].equals(new String("street")) && Integer.parseInt(arrStreet[1])== ++lastInd){//empieza por street
					
						if(arrStreet[2].equals("place") && arrStreet[5].equals("place")){
							if(Integer.parseInt(arrStreet[3]) < places.size() && Integer.parseInt(arrStreet[6]) < places.size()){
								Place source = places.get(Integer.parseInt(arrStreet[3]));
								Place dest = places.get(Integer.parseInt(arrStreet[6]));
							
							
								Direction dir = Direction.UNKNOWN;
								if(arrStreet[4].equalsIgnoreCase(Direction.NORTH.name())){
									dir = Direction.NORTH;
								}else if(arrStreet[4].equalsIgnoreCase(Direction.SOUTH.name())){
									dir = Direction.SOUTH;
								}else if(arrStreet[4].equalsIgnoreCase(Direction.EAST.name())){
									dir = Direction.EAST;
								}else if(arrStreet[4].equalsIgnoreCase(Direction.WEST.name())){
									dir = Direction.WEST;
								}else{
									throw new WrongCityFormatException();
								}
								
								boolean isOpen = (arrStreet[7].equals(new String("open")));
								String code = "";
								if(!isOpen && arrStreet.length > 8){
									code = arrStreet[8];
								}
								Street st = new Street(source,dir,dest,isOpen,code);					
								streets.add(st);
								city.addStreet(st);
							}else{
								throw new WrongCityFormatException();
							}
						}else{
							throw new WrongCityFormatException();
						}
					}else{
						throw new WrongCityFormatException();
					}
				}else{ throw new WrongCityFormatException(); }
				if((line = in.readLine())==null) throw new WrongCityFormatException();
			}
		}else{
			throw new WrongCityFormatException();
		}
	}
}
